
import { toRaw } from 'vue'
// import type { InjectionKey } from 'vue'

import {
  copy 
} from '../base/assign'

// 日志
import {
  stateLog, // 记录容器
  writeLog // 添加一条记录
} from '../base/_log'

import type {
  IState,
  IStateKey,
  IAnyObject,
  IObjectOrFunction
} from '../types/type'

import BaseArray from './base-array'

/**
 * 把属性也变成基类的形式，递归
 * @param target 目标，即 this
 * @param source 来源，value
 */
const copyDeep = (target: IAnyObject, source: IAnyObject) => {

  // Object.keys(source).forEach((key: IStateKey) => {
  for (const key in source) {
    const p = source[key]
    if (Array.isArray(p)) {
      target[key] = new BaseArray(p)
    } else {
      if (typeof p === 'object' && p !== null) {
        target[key] = new BaseObject(p, true)
      } else {
        target[key] = p
      }
    }
  }
}

/**
 * 给对象加上共用函数：$state、$patch、$reset
 * * 可选单层和深层
 * * 单层：对于属性不做处理
 * * 深层：如果属性是对象或者数组，则变成基类的形式
 */
export default class BaseObject implements IState {
  #id: IStateKey
  #isLog: boolean
  // #isModel = true
  // #isObject = true
  #isDeep: boolean // 如果属性类型是对象、数组，是否转换
  #_value: IObjectOrFunction // 初始值或者初始函数

  constructor (objOrFunction: IObjectOrFunction, isDeep = false, id: IStateKey = Symbol('_object'), isLog = false) {
    this.#isDeep = isDeep
    this.#id = id
    this.#isLog = isLog
    if (typeof objOrFunction === 'function'){
      // 记录初始函数
      this.#_value = objOrFunction
      // 设置对象的属性
      if (isDeep) {
        // 需要处理属性，属性类型是array、object的话，会变成基类
        copyDeep(this, objOrFunction())
      } else {
        // 执行函数，浅层拷贝，设置属性
        Object.assign(this, objOrFunction())
      }
    }
    else {
      // 记录初始值的副本，浅层拷贝，只支持单层属性
      this.#_value = Object.assign(objOrFunction)
      // 设置对象的属性
      if (isDeep) {
        // 需要处理属性，属性类型是array、object的话，会变成基类
        copyDeep(this, objOrFunction)
      } else {
        // 对象，浅层拷贝，设置属性
        Object.assign(this, objOrFunction)
      }
    }
  }

  // 操作状态的函数
  /**
   * 获取初始值，如果是函数的话，会调用函数返回结果
   */
  get $value() {
    const val = toRaw(this).#_value
    const re = typeof val === 'function' ? val() : val
    return re
  }

  /**
   * 设置初始值
   */
  set $value(val) {
    toRaw(this).#_value = val
  }

  /**
   * 恢复初始值
   */
  $reset() {
    // 模板里面触发的事件，没有 this
    if (this) {
      writeLog(this, this.$value, '$reset', 3, () => {
        copy(this, this.$value)
      })
    }
  }

  /**
   * 设置新值
   */
  set $state(value: IAnyObject) {
    // 要不要判断 value 的属性是否完整？
    writeLog(this, value, '$state', 5, () => {
      copy(this, value)
    })
  }

  /**
   * 替换部分属性，只支持单层
   */
  async $patch(obj: IObjectOrFunction) {
    writeLog(this, obj, '$patch', 3, async () => {
      if (typeof obj === 'function') {
        // 回调，不接收返回值
        await obj(this)
      } else {
        // 赋值
        copy(this, obj)
      }
    })
    
  }
  
  /**
   * 取原型，不包含内部方法
  */
  $toRaw<T extends IAnyObject>(): T {
    const obj: IAnyObject = {} as IAnyObject
    const tmp: {[key: IStateKey]: any} = toRaw(this)
    Object.keys(tmp).forEach((key: IStateKey) => {
    // for (const key in tmp) {
      if (typeof key === 'symbol') {
        obj[key] = (tmp[key].$toRaw) ? tmp[key].$toRaw() : toRaw(tmp[key])
      } else {
        if ((key as string).substring(0,1) !== '#') {
          obj[key] = (tmp[key].$toRaw) ? tmp[key].$toRaw() : toRaw(tmp[key])
        }
      }
    })
    return obj as T
  }

  /**
   * 获取是否转换
   */
  get $isDeep() {
    return toRaw(this).#isDeep
  }
  
  /**
   * 获取是否深层
   */
  get $id() {
    return toRaw(this).#id
  }
  /**
   * 获取是否记录日志
   */
  get $isLog() {
    return toRaw(this).#isLog
  }
  /**
   * 验证是不是状态
   */
  get $isState() {
    return false
  }
  /**
   * 验证是不是对象类型的基类
   */
  get $isObject() {
    return true
  }
  /**
   * 验证是不是数组类型的基类
   */
  get $isArray() {
    return false
  }
  
  /**
   * 获取日志
   */
  get $logs() {
    if (stateLog[this.$id]) {
      return stateLog[this.$id].log
    } else {
      return []
    }
  }
  
  /**
   * 清空日志
   */
  $clearLog() {
    if (stateLog[this.$id]) {
      stateLog[this.$id].log.length = 0
    }
  }
}